package com.zwl.swagger.plugins;

import com.google.common.base.Optional;
import com.zwl.util.ReflectUtil;
import com.zwl.util.SwaggerSpringUtil;
import com.zwl.util.SwaggerStringUtil;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;
import springfox.documentation.spi.service.contexts.OperationContext;
import springfox.documentation.spi.service.contexts.ParameterExpansionContext;
import springfox.documentation.spring.web.readers.parameter.ModelAttributeParameterMetadataAccessor;

import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.StringJoiner;

/**
 * @author zhangweilin
 * @Description:
 * @date 2021年08月21日 13:40
 */
public interface ContextDescriper {

    /**
     * 读取方法描述
     *
     * @param context
     * @return
     */
    default String getMethodDescription(OperationContext context) {
        Object requestContext = ReflectUtil.getFieldValue(context, "requestContext");
        if (requestContext == null) {
            return "";
        }
        Object handler = ReflectUtil.getFieldValue(requestContext, "handler");
        if (handler == null) {
            return "";
        }
        Object handlerMethod = ReflectUtil.getFieldValue(handler, "handlerMethod");
        if (handlerMethod == null) {
            return "";
        }
        Object description = null;
        try {
            description = ReflectUtil.getFieldValue(handlerMethod, "description");
            if (description == null) {
                return "";
            }
            return description.toString();
        } catch (Exception e) {
//            e.printStackTrace();
            //===兼容低版本spring boot
            Method method = ReflectUtil.getFieldValue(handlerMethod, "method");
            String beanName = ReflectUtil.getFieldValue(handlerMethod, "bean");
            ApplicationContext applicationContext = SwaggerSpringUtil.getApplicationContext();
            AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();
            Class<?> beanTypeClass = autowireCapableBeanFactory.getType(beanName);
            Class<?> beanType = ClassUtils.getUserClass(beanTypeClass);
            String description1 = initDescription(beanType, method);
            return description1;
        }
    }

    default String initDescription(Class<?> beanType, Method method) {
        StringJoiner joiner = new StringJoiner(", ", "(", ")");
        for (Class<?> paramType : method.getParameterTypes()) {
            joiner.add(paramType.getSimpleName());
        }
        return beanType.getName() + "#" + method.getName() + joiner.toString();
    }

    default String getClassDescription(OperationContext context) {
        String methodDescription = getMethodDescription(context);
        if (StringUtils.isEmpty(methodDescription)) {
            return "";
        }
        return methodDescription.substring(0, methodDescription.indexOf("#"));
    }

    default String getFieldsDescription(ModelPropertyContext context) {
        Object beanPropertyDefinition = ReflectUtil.getFieldValue(context, "beanPropertyDefinition");
        if (beanPropertyDefinition != null && beanPropertyDefinition instanceof Optional) {
            Optional optional = (Optional) beanPropertyDefinition;
            if (!optional.isPresent()) {
                return "";
            }
            Object o = optional.get();
            Object _fields = ReflectUtil.getFieldValue(o, "_fields");
            if (_fields == null) {
                return "";
            }
            Object value = ReflectUtil.getFieldValue(_fields, "value");
            if (value == null) {
                return "";
            }
            String fieldsStr = value.toString();
            fieldsStr = fieldsStr.replace("[field ", "").replace("]", "");
            return fieldsStr;
        }
        return "";
    }

    default String getFieldsDescription(ParameterExpansionContext context) {
        Object metadataAccessor = ReflectUtil.getFieldValue(context, "metadataAccessor");
        if (metadataAccessor != null && metadataAccessor instanceof ModelAttributeParameterMetadataAccessor) {
            ModelAttributeParameterMetadataAccessor metadataAccessor1 = (ModelAttributeParameterMetadataAccessor) metadataAccessor;
            Object annotatedElements = ReflectUtil.getFieldValue(metadataAccessor1, "annotatedElements");
            if (annotatedElements != null && annotatedElements instanceof List) {
                List<AnnotatedElement> annotatedElementList = (List<AnnotatedElement>) annotatedElements;
                if (annotatedElementList != null && !annotatedElementList.isEmpty()) {
                    java.util.Optional<AnnotatedElement> fieldOptional = annotatedElementList.stream().filter(e -> e instanceof Field).findFirst();
                    if (!fieldOptional.isPresent()) {
                        return "";
                    }
                    AnnotatedElement annotatedElement = fieldOptional.get();
                    if (annotatedElement != null) {
                        String fieldsDescription = annotatedElement.toString();
                        //格式为 private java.lang.String com.zwl.xxx.model.vo.RobotStoreGrayVo.storeCode
                        Object[] fieldsDescriptionArr = Arrays.stream(fieldsDescription.split(" ")).toArray();
                        if (fieldsDescriptionArr != null && fieldsDescriptionArr.length == 3) {
                            fieldsDescription= (String) fieldsDescriptionArr[2];
                        }
                        //此时格式为 com.zwl.xxx.model.vo.RobotStoreGrayVo.storeCode
                        if (fieldsDescription != null) {
                            fieldsDescription = SwaggerStringUtil.replaceLast(fieldsDescription, "\\.", "#");
                            return fieldsDescription;
                        }
                    }
                }
            }
        }
        return "";
    }

    default Boolean isRequired(String fieldsComment) {
        Boolean required = Boolean.FALSE;
        if (null != fieldsComment && (fieldsComment.startsWith("*") || fieldsComment.endsWith("*"))) {
            required = Boolean.TRUE;
        }
        return required;
    }

}
